package com.miku.blog.aspect;

import com.alibaba.fastjson.JSON;
import com.miku.blog.annotation.SystemLog;
import com.miku.blog.domain.OperationLog;
import com.miku.blog.service.OperationLogService;
import com.miku.blog.utils.IpAddressesUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author shkstart
 * @create ${}YEAR-05-25 23:49
 */
@Slf4j
@Aspect
@Component
public class AspectLog {

    @Autowired
    private OperationLogService operationLogService;

    @Pointcut("@annotation(com.miku.blog.annotation.SystemLog)")
    public void pointCut(){

    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed;
        try {
            beforeHandler(joinPoint);
            proceed = joinPoint.proceed();
            afterHandler(proceed);
        } catch (Throwable throwable) {
//            log.error(">>>>> 出现异常 <<<<<",throwable);
            throw throwable;
        } finally {
            log.info("============ END ============" + System.lineSeparator());
        }
        try {
            operationLogService.addSuccessOperationLog(joinPoint,proceed);
        } catch (Exception exception) {
            log.error(">>>>> 日志添加失败 <<<<<",exception);
            log.error(">>>>> END <<<<<" + System.lineSeparator());
        }
        return proceed;
    }

    private void beforeHandler(ProceedingJoinPoint joinPoint) {
        SystemLog systemLog = getSystemLog(joinPoint);

        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        Map<String, String[]> parameterMap = request.getParameterMap();
        Object[] obj = joinPoint.getArgs();
        for (int i = 0;i < obj.length;i++){
            if (Objects.nonNull(obj[i]) && MultipartFile.class.isAssignableFrom(obj[i].getClass())){
                obj[i] = ((MultipartFile) obj[i]).getOriginalFilename();
            }
        }

        log.info("=========== Start ===========");
        log.info("Request URL        : {}",request.getRequestURL());
        log.info("Request Parameters : {}", JSON.toJSONString(parameterMap));
        log.info("Request Body       : {}", JSON.toJSONString(obj));
        log.info("Request Method     : {}",request.getMethod());
        log.info("Request IP         : {}", IpAddressesUtils.getIp(request));
        log.info("Class Method       : {}.{}({})",joinPoint.getSignature().getDeclaringTypeName(),joinPoint.getSignature().getName(), ((MethodSignature)joinPoint.getSignature()).getParameterNames());
        log.info("Notes              : {}",systemLog.notes());

    }

    private void afterHandler(Object proceed) {
        log.info("Response           : {}",JSON.toJSONString(proceed));
    }

    private SystemLog getSystemLog(ProceedingJoinPoint joinPoint){
        MethodSignature methodSignature
                = (MethodSignature) joinPoint.getSignature();
        SystemLog systemLog
                = methodSignature.getMethod()
                .getAnnotation(SystemLog.class);
        return systemLog;
    }

}
